﻿namespace Jsl.StyleCop.CSharp.MaintainabilityRules
{
    using Jsl.StyleCop.CSharp.UnitTesting;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class TestDisposeComponentsFieldCorrectly : TestBase<RuleAnalyzer>
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="TestDisposeComponentsFieldCorrectly"/> class.
        /// </summary>
        public TestDisposeComponentsFieldCorrectly()
            : base(RuleAnalyzer.DisposeComponentsFieldCorrectly)
        {
        }
        #endregion Constructors

        [TestMethod]
        public void Must_check_if_components_field_is_null()
        {
            this.TestMethod(
                @"protected override void Dispose(bool disposing)
                {
                    if (disposing)
                    {
                        components.Dispose();
                    }
                }")
                .AssertViolation(3, "The components.Dispose must be inside this if: if (this.components != null);")
                .NoMoreViolations();

            this.TestMethod(
                @"protected override void Dispose(bool disposing)
                {
                    if (something == 5)
                    {
                        this.components.Dispose();
                    }
                }")
                .AssertViolation(3, "The components.Dispose must be inside this if: if (this.components != null);")
                .NoMoreViolations();
        }

        [TestMethod]
        public void Can_check_disposing_parameter_as_well_as_components_field()
        {
            this.TestMethod(
                @"protected override void Dispose(bool disposing)
                {
                    if (disposing && (components != null))
                    {
                        components.Dispose();
                    }
                }")
                .NoMoreViolations();

            this.TestMethod(
                @"protected override void Dispose(bool disposing)
                {
                    if (disposing && (this.components != null))
                    {
                        this.components.Dispose();
                    }
                }")
                .NoMoreViolations();
        }

        [TestMethod]
        public void The_components_disposed_should_be_the_only_thing_inside_the_if()
        {
            this.TestMethod(
                @"protected override void Dispose(bool disposing)
                {
                    if (components != null)
                    {
                        components.Dispose();
                        int x = 5;
                    }
                }")
                .AssertViolation(5, "There should only be the this.components.Dispose() inside the if statement.")
                .NoMoreViolations();

            this.TestMethod(
                @"protected override void Dispose(bool disposing)
                {
                    if (this.components != null)
                    {
                        this.components.Dispose();
                        int x = 5;
                    }
                }")
                .AssertViolation(5, "There should only be the this.components.Dispose() inside the if statement.")
                .NoMoreViolations();
        }

        [TestMethod]
        public void Setting_components_to_null_is_OK()
        {
            this.TestMethod(
                @"protected override void Dispose(bool disposing)
                {
                    if (components != null)
                    {
                        components.Dispose();
                        components = null;
                    }
                }")
                .NoMoreViolations();

            this.TestMethod(
                @"protected override void Dispose(bool disposing)
                {
                    if (this.components != null)
                    {
                        this.components.Dispose();
                        this.components = null;
                    }
                }")
                .NoMoreViolations();
        }

        [TestMethod]
        public void Comments_are_ignored()
        {
            this.TestMethod(
                @"protected override void Dispose(bool disposing)
                {
                    if (components != null)
                    {
                        components.Dispose();
                        // Crazy comment...
                    }
                }")
                .NoMoreViolations();
        }

        [TestMethod]
        public void The_components_dispose_should_be_in_an_IF_statement()
        {
            this.TestMethod(
                @"protected override void Dispose(bool disposing)
                {
                    components.Dispose();
                }")
                .AssertViolation(3, "The components.Dispose must be inside this if: if (this.components != null);")
                .NoMoreViolations();
        }

        [TestMethod]
        public void No_code_to_dispose_the_components_field_so_no_violations()
        {
            this.TestMethod(
                @"protected override void Dispose(bool disposing)
                {
                    if (disposing)
                    {
                        this.SomeField.Dispose();
                    }

                    base.Dispose(disposing);
                }")
                .NoMoreViolations();
        }

        [TestMethod]
        public void Not_the_Dispose_method_so_no_violations()
        {
            // Missing disposing parameter.
            this.TestMethod(
                @"protected override void Dispose()
                {
                }")
                .NoMoreViolations();

            // Not the correct method name.
            this.TestMethod(
                @"protected override void DisposeX(bool disposing)
                {
                }")
                .NoMoreViolations();

            // Not an override.
            this.TestMethod(
                @"protected void Dispose(bool disposing)
                {
                }")
                .NoMoreViolations();

            // Not protected.
            this.TestMethod(
                @"public override void Dispose(bool disposing)
                {
                }")
                .NoMoreViolations();
        }
    }
}